package org.bhf.validation.annotations;

/**
 * Copyright (c) 2007, Blue Hole Software. All rights reserved.
 * Code licensed under the Apache 2.0 License:
 * http://www.apache.org/licenses/
 */

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * We keep a registry of validation annotations to reduce reflection to a lookup. Because these
 * annotations are small and linked to code, the registry will be much smaller than the loaded
 * code: we don't need to worry about the registry size.
 * @exclude
 */
public class ValidatorRegistry
{
    private static final Map<String, Annotation> validators = new HashMap<String, Annotation>();

    /**
     * Register a validator.
     *
     * @param validator Validator annotation
     * @param method Method declaring the validator.
     * @return Key under which the validator was registered.
     */
    public static String        register( final Annotation validator, final Method method )
    {
        final String key = generateKey( validator, method );

        synchronized( validators )
        {
            if( validators.get( key ) == null )
                validators.put( key, validator );
        }

        return key;
    }

    /**
     * Lookup a previously registered validator.
     *
     * @param key Key returned by <code>register()</code>
     * @param clazz Class of the registered validator
     * @return Validator annotation
     * @throws java.util.NoSuchElementException The validator was not registered
     */
    public static<T extends Annotation> T lookup( final String key, final Class<T> clazz )
    {
        synchronized( validators )
        {
            final Annotation a = validators.get( key );
            if( a == null )
                throw new NoSuchElementException( key );
            return clazz.cast( a );
        }
    }

    //
    // Private
    //

    private static String   generateKey( final Annotation validator, final Method method )
    {
        return method.getDeclaringClass().getName() + '.' + method.getName() + '.' + validator.annotationType().getName();
    }
}
